Skip to content

feat: add support for feed scoped notifications - #1780

Merged
davidgamez merged 13 commits into
mainfrom
worktree-issue-1778-feed-scoped-subscriptions
Jul 29, 2026
Merged

feat: add support for feed scoped notifications#1780
davidgamez merged 13 commits into
mainfrom
worktree-issue-1778-feed-scoped-subscriptions

Conversation

@davidgamez

@davidgamez davidgamez commented Jul 27, 2026

Copy link
Copy Markdown
Member

Summary:
Core changes:

  • Add feed_ids to NotificationSubscription and CreateNotificationSubscriptionRequest supporting feed related notifications (feed.url_updated, feed.url_availability and feed.coverage)
  • /v1/notifications - Fully implemented
  • Gated endpoints under isNotificationsEnabled flag:
    • DELETE /v1/subscriptions/{id}
    • POST, PUT, DELETE /v1/user/subscriptions
  • Filter out admin.event_summary for users that don't have isAdminSummarySubscriptionEnabled flag.

From our AI friend:

This pull request implements feed-scoped notification subscriptions, feature flag gating for notification management, and refines the handling of notification types and subscriptions. The main changes include enforcing feature flag checks for all subscription actions, supporting feed-scoped notification types with validation and join-table persistence, and improving the database cascade behavior for child collections. The implementation also introduces helper functions and refactors the API to return only allowed notification types to users.

Feature flag gating and validation:

  • All subscription management actions (create, update, delete) now require the isNotificationsEnabled feature flag for the user, enforced via new helper methods and error messages. The special admin.event_summary notification type also requires an additional feature flag (isAdminSummarySubscriptionEnabled). [1] [2] [3] [4] [5]
  • The public (unauthenticated) delete endpoint for subscriptions also enforces feature flag gating based on the subscription owner's flags.

Feed-scoped notification subscriptions:

  • Support for feed-scoped notification types (feed.url_updated, feed.url_availability, feed.coverage) is added, requiring a non-empty list of feed IDs for these types. The feed IDs are validated for existence and persisted in the notification_subscription_feed join table. [1] [2] [3] [4]
  • The user's subscriptions response now includes the list of targeted feed IDs, and the code ensures stable, deduplicated ordering. [1] [2]

Database and ORM improvements:

  • The SQLAlchemy event listener now enables delete-orphan and passive_deletes for both notification_logs and notification_subscription_feeds collections, ensuring proper cascading deletes and orphan removal. [1] [2]
  • Added a helper to find unknown feed IDs by querying the feeds database, used to validate input.

API and model refactoring:

  • Implemented the notifications API to return only the notification types the user is allowed to subscribe to, filtering based on feature flags. [1] [2]
  • Added a new implementation for converting ORM NotificationType objects to Pydantic models.

Testing:

  • Updated tests to patch the new feature flag checks, ensuring they do not block test execution.
    Expected behavior:

Explain and/or show screenshots for how you expect the pull request to work in your testing (in case other devices exhibit different behavior).

Testing tips:

Tested in dev with the following cURL commands:

  • Get the list of notifications:
curl --request GET \
  --url https://api-dev.mobilitydatabase.org//v1/notifications \
  --header 'Authorization: Bearer '

Response:

[
  {
    "id": "admin.event_summary",
    "description": "Daily digest sent to admin subscribers summarising how many notification events were dispatched, failed, or skipped during the previous dispatcher run."
  },
  {
    "id": "api.announcements",
    "description": "API announcements"
  },
  {
    "id": "feed.url_updated",
    "description": "Fired when a feed URL changes in-place (url_replaced) or a feed is deprecated and redirected to a new feed (feed_redirected)."
  }
]
  • Create subscription:
curl --request POST \
  --url https://api-dev.mobilitydatabase.org/v1/user/subscriptions \
  --header 'Authorization: Bearer ' \
  --header 'content-type: application/json' \
  --data '{"notification_id":"feed.url_updated","feed_ids":["mdb-100"]}'

Response:

{
  "id": "f91224e8-9466-4825-a44f-bf78eec1813a",
  "user_id": "tbUz14OLEIf0gsGw5ecbEbS34xQ2",
  "notification_id": "feed.url_updated",
  "active": true,
  "created_at": "2026-07-28T19:03:45.301170Z",
    "feeds": [
      {
        "feed_id": "mdb-100",
        "data_type": "gtfs",
        "provider": "Anaheim Resort Transportation (ART)",
        "feed_name": ""
      }
    ]
}
  • Get user's subscriptions:
curl --request GET \
  --url https://api-dev.mobilitydatabase.org/v1/user/subscriptions \
  --header 'Authorization: Bearer '

Response:

[
  {
    "id": "0f3e9d1c-724d-473f-8c0d-1082328b79be",
    "user_id": "tbUz14OLEIf0gsGw5ecbEbS34xQ2",
    "notification_id": "admin.event_summary",
    "active": true,
    "created_at": "2026-06-22T22:48:05.198631Z",
    "feed_ids": null
  },
  {
    "id": "c155ca84-958a-44ad-92ab-d35766b748eb",
    "user_id": "tbUz14OLEIf0gsGw5ecbEbS34xQ2",
    "notification_id": "api.announcements",
    "active": true,
    "created_at": "2026-06-24T19:00:34.901883Z",
    "feed_ids": null
  },
  {
    "id": "f91224e8-9466-4825-a44f-bf78eec1813a",
    "user_id": "tbUz14OLEIf0gsGw5ecbEbS34xQ2",
    "notification_id": "feed.url_updated",
    "active": true,
    "created_at": "2026-07-28T19:03:45.301170Z",
    "feeds": [
      {
        "feed_id": "mdb-100",
        "data_type": "gtfs",
        "provider": "Anaheim Resort Transportation (ART)",
        "feed_name": ""
      }
    ]
  }
]

Please make sure these boxes are checked before submitting your pull request - thanks!

  • Run the unit tests with ./scripts/api-tests.sh to make sure you didn't break anything
  • Add or update any needed documentation to the repo
  • Format the title like "feat: [new feature short description]". Title must follow the Conventional Commit Specification(https://www.conventionalcommits.org/en/v1.0.0/).
  • Linked all relevant issues
  • Include screenshot(s) showing how this pull request works and fixes the issue(s)

@davidgamez
davidgamez marked this pull request as ready for review July 28, 2026 19:26
Comment thread docs/UserServiceAPI.yaml
Comment on lines 394 to +412
@@ -400,6 +400,16 @@ components:
type: string
description: The notification type to subscribe to.
example: "feed.published"
feed_ids:
type: array
items:
type: string
description: >
Feed stable IDs to subscribe to. Required (non-empty) for the
feed-scoped notification types feed.url_updated,
feed.url_availability and feed.coverage; must be omitted or empty
for other types. Validation is enforced in code, not the schema.
example: ["mdb-1", "mdb-42"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we should add a description field so that when listing the notifications it could be more descriptive than

mdb-1 - feed.availability
and more like
TTC (gtfs) - feed.availability

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great observation. Instead of a description that can be rigid, what about returning the following fields:

  • data_type
  • provider
  • feed_name
    The consumer can create the description and handle edge cases such as character counts.

@Alessandro100 Alessandro100 Jul 29, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm on board, since it includes more feed data, feeds_data would be a more suitable name

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added feed's metadata, example:

  {
    "id": "f91224e8-9466-4825-a44f-bf78eec1813a",
    "user_id": "tbUz14OLEIf0gsGw5ecbEbS34xQ2",
    "notification_id": "feed.url_updated",
    "active": true,
    "created_at": "2026-07-28T19:03:45.301170Z",
    "feeds": [
      {
        "feed_id": "mdb-100",
        "data_type": "gtfs",
        "provider": "Anaheim Resort Transportation (ART)",
        "feed_name": ""
      }
    ]
  }

@Alessandro100 Alessandro100 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@davidgamez
davidgamez merged commit 06f1ba7 into main Jul 29, 2026
21 of 22 checks passed
@davidgamez
davidgamez deleted the worktree-issue-1778-feed-scoped-subscriptions branch July 29, 2026 19:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support feed-scoped notification subscriptions (feed.url_updated, feed.url_availability, feed.coverage)

2 participants